<?php

App::uses('AppController', 'Controller');
App::uses('AuthComponent', 'Controller/Component');

class CoreInstallationController extends AppController {

    static $iconCls = "cake-plain";
    public $components = array('Session', 'RequestHandler');

    function __construct($request = null, $response = null) {
        parent::__construct($request, $response);
        $this->constructClasses();
        $key = $this->Session->read('installationKey');
        if ($this->checkPermition('admin') || !empty($key)) {
            $this->Session->write('installationKey', '');
            $this->Session->delete('installationKey');
        } else {
            $this->Session->destroy();
            $this->redirect($this->Auth->logout());
        }
    }

    static $newInstall_iconCls = "disk--plus";

    function newInstall() {

        //echo __LINE__;exit;
    }

    function testConnection($nameDb, $userDb, $passDb, $addressDb) {
        if ($con = mysql_connect($addressDb, $userDb, $passDb)) {
            if (mysql_select_db($nameDb, $con)) {
                return true;
            }
        }
        return false;
    }

    function testConnectionJson() {
        error_reporting(0);
        $this->RequestHandler->respondAs('json');
        $this->autoRender = false;
        $connection = $this->testConnection($_POST['nameDb'], $_POST['userDb'], $_POST['passDb'], $_POST['addressDb']);
        if ($connection) {
            $this->Session->write('nameDb', $_POST['nameDb']);
            $this->Session->write('userDb', $_POST['userDb']);
            $this->Session->write('passDb', $_POST['passDb']);
            $this->Session->write('addressDb', $_POST['addressDb']);
            $this->Session->write('mysqlBinPath', $_POST['mysqlBinPath']);
        }
        echo json_encode($connection);
    }

    function useDump() {
        $this->layout = 'ajax';
        /*
          chdir($this->Session->read('mysqlBinPath'));
          //var_dump(getcwd());
          //set_include_path($this->mysqlBinPath);
          $fields = get_class_vars('DATABASE_CONFIG');
          $command = "mysql --user={$this->Session->read('userDb')} --password={$this->Session->read('passDb')} --host={$this->Session->read('addressDb')} {$this->Session->read('nameDb')}  < " . ROOT . DS . "coreSqlDump.sql";
          $descriptorspec = array(
          0 => array("pipe", "r"), // stdin is a pipe that the child will read from
          1 => array("pipe", "w"), // stdout is a pipe that the child will write to
          2 => array("pipe", "w")     // stderr is a pipe that the child will write to
          );
          $process = proc_open($command, $descriptorspec, $pipes);
          if (is_resource($process)) {
          $stdin = stream_get_contents($pipes[0]);
          $stdout = stream_get_contents($pipes[1]);
          $stderr = stream_get_contents($pipes[2]);
          fclose($pipes[0]);
          fclose($pipes[1]);
          fclose($pipes[2]);
          // It is important that you close any pipes before calling proc_close in order to avoid a deadlock
          proc_close($process);
          $return = array($command, $stdin, $stdout, $stderr);
          } else {
          $output = shell_exec($command);
          $return = array($output, $command);
          }
          echo implode("<br>", $return);
         * 
         */
        mysql_connect($this->Session->read('addressDb'), $this->Session->read('userDb'), $this->Session->read('passDb')) or die("Error connecting to MySQL server: " . mysql_error());
        mysql_select_db($this->Session->read('nameDb'));

        $filename = ROOT . DS . "coreSqlDump.sql";
        // Temporary variable, used to store current query
        $templine = $msg = '';
        // Read in entire file
        $lines = file($filename);
        // Loop through each line
        foreach ($lines as $line) {
            // Skip it if it's a comment
            if (substr($line, 0, 2) == '--' || $line == '')
                continue;

            // Add this line to the current segment
            $templine .= $line;
            // If it has a semicolon at the end, it's the end of the query
            if (substr(trim($line), -1, 1) == ';') {
                // Perform the query
                if(mysql_query($templine)){
                    $msg .= ($templine);
                }else{
                    $msg .= ('<div class="error">Error performing query ' . $templine . ': ' . mysql_error() . '</div>');
                }
                // Reset temp variable to empty
                $templine = '';
            }
        }
        echo "<pre>{$msg}</pre>";
        exit;
    }

    function createDump() {
        $this->layout = 'ajax';
        $this->setModulesAndTablesList();

        chdir($this->Session->read('mysqlBinPath'));
        //var_dump(getcwd());
        //set_include_path($this->mysqlBinPath);
        $fields = get_class_vars('DATABASE_CONFIG');
        $reset = $this->Session->read('setForReset');
        $noData = (empty($reset) ? "" : "--no-data");
        $command = "mysqldump --user={$fields['default']['login']} --password={$fields['default']['password']} --host={$fields['default']['host']} --databases {$fields['default']['database']} --add-drop-table --tables  " . implode(' ', $this->Session->read('tables')) . " --no-create-db {$noData}  > " . ROOT . DS . "coreSqlDump.sql";
        $descriptorspec = array(
            0 => array("pipe", "r"), // stdin is a pipe that the child will read from
            1 => array("pipe", "w"), // stdout is a pipe that the child will write to
            2 => array("pipe", "w")     // stderr is a pipe that the child will write to
        );
        $process = proc_open($command, $descriptorspec, $pipes);
        if (is_resource($process)) {
            $stdin = stream_get_contents($pipes[0]);
            $stdout = stream_get_contents($pipes[1]);
            $stderr = stream_get_contents($pipes[2]);
            fclose($pipes[0]);
            fclose($pipes[1]);
            fclose($pipes[2]);
            // It is important that you close any pipes before calling proc_close in order to avoid a deadlock
            proc_close($process);
            $return = array($command, $stdin, $stdout, $stderr);
        } else {
            $output = shell_exec($command);
            $return = array($output, $command);
        }
        echo implode("<br>", $return);
        exit;
    }

    static $block_createBackup_iconCls = "disk--arrow";

    function block_createBackup() {
        //$msg = implode("<br>", $this->createDump());
        //$msg .= $this->createZip();
        //$this->set('msg', $msg);
        App::import('Controller', 'CoreModules');
        $coreModule = new CoreModulesController();
        $modules = $coreModule->listModules();
        $this->set('modules', $this->indexAndValueTheSame($modules));
    }

    function createZip() {
        $this->layout = 'ajax';
        ini_set('max_execution_time', 120);
        $zip_file = ROOT . DS . '..' . DS . date('Y-m-d-H-i-s-') . 'coreCake.zip';
        $msg = "Compacting ZIP: " . ROOT . "<br>";
        if ($handle = opendir(ROOT)) {
            $zip = new ZipArchive();

            if ($zip->open($zip_file, ZIPARCHIVE::CREATE) !== TRUE) {
                exit("cannot open <$zip_file>\n");
            }

            while (false !== ($file = readdir($handle))) {
                if (
                        preg_match('/.*[.]$/', $file) ||
                        preg_match('/^.*nbproject$/', $file) ||
                        preg_match('/^.*cache$/', $file) ||
                        preg_match('/^.*logs$/', $file) ||
                        preg_match('/^.*sessions$/', $file) ||
                        preg_match('/^.*tests$/', $file) ||
                        preg_match('/^.*\.svn$/', $file) ||
                        preg_match('/^.*database\.php$/', $file)
                ) {
                    $msg .= "<span style='color:#780;'>{$file} Detected will be ignored<br></span>";
                } else {
                    if (is_dir(ROOT . DS . $file)) {
                        //$zip->addEmptyDir(ROOT . DS . $file);
                        $msg .= $this->addFilesInDir($zip, ROOT . DS . $file);
                    } else {
                        $msg .= $zip->addFile(ROOT . DS . $file, $this->localZipFileName(ROOT . DS . $file));
                        $msg .= ROOT . DS . "$file<br>\n";
                    }
                }
            }
            $databaseCode = '<?php
                        class DATABASE_CONFIG {
                            public $default = array(
                                \'datasource\' => \'DummySource\',
                                \'database\' => \'\'
                            );
                        }';
            $zip->addFromString("app" . DS . "Config" . DS . "database.php", $databaseCode);
            $msg .= $this->createEmptyDirs($zip, ROOT . DS . "app" . DS . "tmp");
            closedir($handle);
            $msg .= "numfiles: " . $zip->numFiles . "<br>\n";
            $msg .= "status:" . $zip->status . "<br>\n";
            $zip->close();
            $msg .= 'Zip File:' . $zip_file . "<br>\n";
        }
        echo $msg;
        exit;
    }

    private function createEmptyDirs($zip, $path) {
        if (preg_match('/.*[.]$/', $path)) {
            return false;
        } else {
            $msg = "";
            if ($handle = opendir($path)) {
                $msg .= "<span style='color:#090;'>" . $path . " Opened<br>\n</span>";
                while (false !== ($file = readdir($handle))) {
                    if (preg_match('/.*[.]$/', $file)) {
                        $msg .= "<span style='color:#900;'>" . $path . DS . $file . " Dir Ignored<br>\n</span>";
                        continue;
                    } else
                    if (is_dir($path . DS . $file)) {
                        $zip->addEmptyDir($this->localZipFileName($path . DS . $file));
                        $msg .= "<span style='color:#090;'>" . $path . DS . $file . " Dir Created<br>\n</span>";
                        $this->createEmptyDirs($zip, $path . DS . $file);
                    }
                }
            } else {
                $msg .= "<span style='color:#A00;'>" . $path . " Could Not Open</span><br>\n";
            }
            return $msg;
        }
    }

    private function addFilesInDir($zip, $path) {
        if (
                preg_match('/.*[.]$/', $path) ||
                preg_match('/^.*nbproject$/', $path) ||
                preg_match('/^.*cache$/', $path) ||
                preg_match('/^.*logs$/', $path) ||
                preg_match('/^.*sessions$/', $path) ||
                preg_match('/^.*tests$/', $path) ||
                preg_match('/^.*\.svn$/', $path) ||
                preg_match('/^.*database\.php$/', $path)
        ) {
            return "<span style='color:#780;'>{$path} Detected will be ignored<br></span>";
        }
        $msg = "";
        if ($handle = opendir($path)) {
            $msg .= "<span style='color:#090;'>" . $path . " Opened<br>\n</span>";
            while (false !== ($file = readdir($handle))) {
                if (is_dir($path . DS . $file)) {
                    //$zip->addEmptyDir($path . DS . $file);
                    $this->addFilesInDir($zip, $path . DS . $file);
                } else if ($this->detectIfModuleIsSelectedForZip($path . DS . $file)) {
                    $zip->addFile($path . DS . $file, $this->localZipFileName($path . DS . $file));
                    $msg .= $path . DS . "$file<br>\n";
                } else {
                    $msg .= "<span style='color:#A90;'>" . $path . DS . $file . " not added</span><br>\n";
                }
            }
        } else {
            $msg .= "<span style='color:#A00;'>" . $path . " Could Not Open</span><br>\n";
        }
        return $msg;
    }

    private function localZipFileName($fileName) {
        return str_replace(ROOT . DS, "", $fileName);
    }

    public function createDatabaseFile() {
        $this->layout = 'ajax';
        $dir = APP . DS . "Config" . DS;
        $file = "{$dir}database.php";
        $newFile = "{$dir}_database.php";
        if (rename($file, $newFile)) {
            $code = "<?php
                        class DATABASE_CONFIG {
                            public \$default = array(
                                'datasource' => 'Database/Mysql',
                                'persistent' => false,
                                'host' => '{$this->Session->read('addressDb')}',
                                'login' => '{$this->Session->read('userDb')}',
                                'password' => '{$this->Session->read('passDb')}',
                                'database' => '{$this->Session->read('nameDb')}',
                                'prefix' => '',
                                'encoding' => 'utf8',
                            );
                        }
                        ";
            $bytes = file_put_contents($file, $code);
            chmod($file, 0660);
            echo __("%s bytes writen<br> <pre>%s</pre>", $bytes, htmlentities($code));
            $this->Session->write('installationKey', 1);
            exit;
        } else {
            echo __("Could not rename %s file", $file);
            exit;
        }
    }

    private function indexAndValueTheSame($array, $removeS = false) {
        $newArray = array();
        foreach ($array as $value) {
            if ($removeS) {
                $value = rtrim($value, "s");
            }
            $newArray[$value] = $value;
        }
        return $newArray;
    }

    private function setModulesAndTablesList() {
        if (empty($_POST['data']['CoreModules'])) {
            echo __('You Need to select the module(s) you need');
            exit;
        }
        $this->Session->write('modules', $_POST['data']['CoreModules']);
        $this->Session->write('setForReset', @$_POST['data']['setForReset']);
        $this->Session->write('mysqlBinPath', $_POST['data']['mysqlBinPath']);
        $tables = array();
        foreach ($_POST['data']['CoreModules'] as $value) {
            App::import('Controller', $value);
            if (empty($value)) {
                continue;
            }
            try {
                eval("\$object = new {$value}Controller();");
                eval("\$schema = \$object->{$object->modelClass}->schema();");
                if (!empty($schema)) {
                    eval("\$tableName = \$object->{$object->modelClass}->table;");
                    $tables[] = $tableName;
                }
            } catch (Exception $e) {
                
            }
        }
        $this->Session->write('tables', $tables);
    }

    private function detectIfModuleIsSelectedForZip($fileName) {
        if (empty($_POST['data']['CoreModules'])) {
            echo __('You Need to select the module(s) you need');
            exit;
        }
        if (preg_match("/(app.*Plugin)|(lib.Cake).*/i", $fileName)) {
            return true;
        }
        $pattern = 'app.*(Controller|View|Model|Test).*';
        //echo $fileName, "<br>/".addslashes($pattern)."/i", "<br><br>";
        // if it is a Controller or Controller or View or Model or Test verify if it is selected to copy
        if (preg_match("/" . addslashes($pattern) . "/i", $fileName)) {
            $module = implode("|", $this->indexAndValueTheSame($_POST['data']['CoreModules'], true));
            $pattern2 = 'app.*(Controller|View|Model|Test).*(' . $module . '|AppModel|Datasource|Behavior|AppController|Component|Helper|Layouts|Pages|ScaffoldsAppModel|Datasource|Behavior|AppController|Component|Helper|Layouts|Pages|Scaffolds).*';
            //echo $fileName, "<br>/".addslashes($pattern2)."/i", "<br><br>";
            // if it is a Controller or Controller or View or Model or Test verify if it is selected to copy
            if (preg_match("/" . addslashes($pattern2) . "/i", $fileName)) {
                //echo "<br>", $fileName, "<br><br>";
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    static $block_resetDatabaseAndFiles_iconCls = "arrow-circle-135-left";

    function block_resetDatabaseAndFiles() {
        
    }

    public function resetDatabaseAndFiles() {
        $this->layout = 'ajax';
        echo $this->reset();
        exit;
    }

    private function reset() {
        //make a backup before run this
        //$this->createDump();

        App::uses('ConnectionManager', 'Model');
        $db = ConnectionManager::getDataSource('default');
        $db->setConfig();
        $tables = $db->listSources();
        $msg = print_r($tables, true);

        // get any model
        App::import('Model', 'CoreBlocksModule');
        $coreBlocksModule = new CoreBlocksModule();
        $coreBlocksModule->create();

        //truncate all tables
        foreach ($tables as $value) {
            $query = "TRUNCATE TABLE {$value};";
            $coreBlocksModule->query($query);
            $msg .= $query . "\n";
        }

        //create a site 
        $query = "INSERT INTO `core_sites` VALUES (1,'Main Site','Site Created by Reset Button','default.ctp','" . Router::url('/', true) . "','a','Core','','',NULL,NULL);";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        //install all modules
        App::import('Controller', 'CoreModules');
        $coreModule = new CoreModulesController();
        $modules = array('pages') + $coreModule->listModules();
        foreach ($modules as $value) {
            $query = "INSERT INTO `core_modules` VALUES (NULL,'{$value}','a','',NULL,NULL);";
            $coreBlocksModule->query($query);
            $msg .= $query . "\n";
        }

        //create a admin group and public group
        $query = "INSERT INTO `core_groups` VALUES (1,'Administrator','Administrator Group Created By Reset Button','a',0,NULL,NULL), (2,'Public','If you not logged you will be in this group','a',1,NULL,NULL);";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        //create a admin user
        $query = "INSERT INTO `core_users` VALUES (1,'admin','" . AuthComponent::password('123') . "','NULL','a',NULL,NULL);";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        //put the user in the admin group
        $query = "INSERT INTO `core_users_groups` VALUES (NULL,1,1);";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        // create group privileges
        foreach ($modules as $key => $value) {
            $query = "INSERT INTO `core_privileges_groups_modules` VALUES (NULL,1," . ($key + 1) . ",'','','1',NULL,NULL);";
            $coreBlocksModule->query($query);
            $msg .= $query . "\n";
        }

        //create a block to put a menu on the left
        $query = "INSERT INTO `core_blocks` VALUES (1,1,'CoreModules/block_accordion_modules','List all blocks on the left','l',1,'',NULL,'a',NULL,NULL),(2,1,'CoreUsers/block_login_small','Left Small Login','l',2,'',NULL,'a',NULL,NULL)";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        // create a header block
        $html = '<div id="top">
                <a href="<?php echo $this->Html->url(array(\'controller\' => \'pages\', \'action\' => \'index\')); ?>">
                    <div class="logo" style="background-image: url(<?php echo $this->Html->url(\'../img/Core/gear48.png\'); ?>);"></div>
                    <h1 style="background-color: transparent;">Core CakePHP</h1>
                    <h2 style="background-color: transparent;">Easy and Fancy</h2>
                </a>
            </div>';
        $query = "INSERT INTO `core_blocks` VALUES (3,1,'CoreBlocks/block_raw_text','Core header','t',2,'','" . str_replace("'", "\\'", serialize(array('text' => $html))) . "','a',NULL,NULL)";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        // put the block on the group
        $query = "INSERT INTO `core_groups_blocks` VALUES (1,1,1), (2,1,2), (3,2,2), (2,1,3), (3,2,3);";
        $coreBlocksModule->query($query);
        $msg .= $query . "\n";

        // put a block module
        foreach ($modules as $key => $value) {
            $query = "INSERT INTO `core_blocks_modules` VALUES (NULL," . ($key + 1) . ",1), (NULL," . ($key + 1) . ",2), (NULL," . ($key + 1) . ",3);";
            $coreBlocksModule->query($query);
            $msg .= $query . "\n";
        }

        return htmlentities($msg);
    }

}

?>
